package ch.ethz.fcl.metrobuzz.data.transit;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xml.sax.Attributes;

import ch.ethz.fcl.metrobuzz.algorithm.network.shortest_path.public_transport.Walk;
import ch.ethz.fcl.metrobuzz.data.MBData;
import ch.ethz.fcl.metrobuzz.data.scene.basemap.Edge;
import ch.ethz.fcl.metrobuzz.data.singapore.SGMRTStations;
import ch.ethz.fcl.metrobuzz.tools.MBTools;

/**
 * public transit network
 * 
 * transit lines -> transit routes -> transit paths -> transit events
 * 
 * @author ZengWei
 * 
 */
public class PublicTransit {
	private MBData data;

	private List<Stop> stops = null;
	private List<TransitLine> lines = null;
	// record which edges are passed by buses or MRTs
	private List<Edge> transitEdgeList = null;

	// map of stop id to stop
	private Map<String, Stop> idStopMap = null;

	// map of stop id to node name
	// XXX:?
	private Map<String, String> nameIdMap = null;

	// map of stop name to stop
	private Map<String, Stop> nameStopMap = null;

	private Map<String, TransitLine> lineMap = null;

	private int transitLinesRead = 0;

	// set true for FlowMapView
	private boolean addStopToNode = true;

	public PublicTransit(MBData data) {
		this.data = data;

		stops = new ArrayList<Stop>();
		lines = new ArrayList<TransitLine>();
		transitEdgeList = new ArrayList<Edge>();

		idStopMap = new HashMap<String, Stop>();
		nameIdMap = new HashMap<String, String>();
		nameStopMap = new HashMap<String, Stop>();

		lineMap = new HashMap<String, TransitLine>();
	}

	public void addStops(Attributes attributes) {
		String id = attributes.getValue("id");
		int spaceIndex = id.indexOf("_r");
		if (spaceIndex != -1) {
			id = id.substring(0, spaceIndex);
		}

		if (id.equals("EW16") || id.equals("NE3"))
			id = "EW16/NE3";

		if (id.equals("BP1") || id.equals("NS4"))
			id = "BP1/NS4";

		String x = attributes.getValue("x");
		String y = attributes.getValue("y");
		String linkRefId = attributes.getValue("linkRefId");
		String name = attributes.getValue("name");

		Float fx = Float.parseFloat(x);
		Float fy = Float.parseFloat(y);

		Edge refEdge = data.getScene().getEdge(linkRefId);
		Stop stop = new Stop(id, refEdge, fx, fy);
		stop.init(data);

		if (idStopMap.get(stop.getId()) == null) {
			idStopMap.put(stop.getId(), stop);
			stops.add(stop);
		}

		if (!nameIdMap.containsKey(id))
			nameIdMap.put(id, stop.getId());

		if (SGMRTStations.isMRTStation(id)) {
			data.getSGInfo().addMRTStation(id, name);
		}

		if (!MBTools.isNumeric(id) && nameStopMap.get(name) == null) {
			nameStopMap.put(name, stop);
		}

		if (addStopToNode)
			data.getScene().addStopAsNode(stop);
	}

	public void addTransitLines(TransitLine line) {
		String id = line.getId();
		if (lineMap.get(id) == null) {
			lineMap.put(id, line);
			lines.add(line);
		}
	}

	public void addTransitEdge(Edge e) {
		if (!transitEdgeList.contains(e))
			transitEdgeList.add(e);
	}

	public void init() {
		// map stop positions onto screen bound, if stop is not added to node
		if (!addStopToNode)
			for (Stop stop : stops) {
				stop.setX(data.getScene().getBound().normalizeX(stop.getX()));
				stop.setY(data.getScene().getBound().normalizeY(stop.getY()));
			}

		for (Stop stop : stops) {
			for (Stop otherStop : stops)
				if (stop != otherStop) {
					float walkCost = Walk.walkCost(data, stop.toPoint(),
							otherStop.toPoint());
					// if walk cost less than 10 minutes
					if (walkCost <= Walk.MAXIMUM_WALK_LIMIT)
						stop.addCloseStop(otherStop, walkCost);
				}
		}

		for (TransitLine line : lines)
			for (TransitRoute route : line.getRoutes())
				route.calStopDist();
	}

	public int getTransitLinesRead() {
		return transitLinesRead;
	}

	public List<Stop> getStops() {
		return stops;
	}

	public Stop getStopByStopName(String stopName) {
		if (stopName.equals("Harbour Front"))
			stopName = "HarbourFront";
		else if (stopName.equals("South VIEW"))
			stopName = "South View";
		return nameStopMap.get(stopName);
	}

	public Stop getStopByStopId(String stopId) {
		int index = stopId.indexOf("_r");
		if (index != -1)
			stopId = stopId.substring(0, index);

		if (stopId.equals("EW16") || stopId.equals("NE3"))
			stopId = "EW16/NE3";

		if (stopId.equals("NS4") || stopId.equals("BP1"))
			stopId = "BP1/NS4";

		return idStopMap.get(nameIdMap.get(stopId));
	}

	public Stop getStopByNodeId(String nodeId) {
		if (nodeId.equals("EW16") || nodeId.equals("NE3"))
			nodeId = "EW16/NE3";

		if (nodeId.equals("NS4") || nodeId.equals("BP1"))
			nodeId = "BP1/NS4";

		return idStopMap.get(nodeId);
	}

	public List<TransitLine> getLines() {
		return lines;
	}

	public List<Edge> getTransitEdges() {
		return transitEdgeList;
	}

	public TransitLine getLine(String lineName) {
		return lineMap.get(lineName);
	}
}
